package com.hitqz.robot.driver.netty.handler;

import cn.hutool.extra.spring.SpringUtil;
import com.hitqz.robot.api.common.dto.robot.RobotOnlineEventDto;
import com.hitqz.robot.driver.communication.NetworkServiceThreadPool;
import com.hitqz.robot.driver.netty.protocol.message.GfMessage;
import com.hitqz.robot.driver.netty.router.GfMessageRouter;
import com.hitqz.robot.driver.netty.strategy.GfMessageHandlerStrategy;
import com.hitqz.robot.driver.util.GfToolkit;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;

@Slf4j
public class GfMessageHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        // 处理接收到的消息，这里假设 msg 是你解码后的对象
        if (msg instanceof GfMessage message) {
            // 在这里处理消息，比如解析内容、处理业务逻辑等
            handleMessage(ctx, message);
        } else {
            log.warn("[gf]channel read unknown message type: {}", msg.getClass().getName());
        }
    }

    // 处理消息的业务逻辑
    private void handleMessage(ChannelHandlerContext ctx, GfMessage message) {
        // 根据命令进行分发
        NetworkServiceThreadPool.dealMessage(() -> {
            //异步分发给不同的 handler 用到反射,handler主线程不要做耗时间的操作,否则会阻塞线程
            byte[] data = message.getData();
            byte mainCmd = data[0];
            GfMessageHandlerStrategy strategy = GfMessageRouter.getHandlerStrategy(mainCmd);
            if (strategy == null) {
                this.simpleHandle(ctx, message);
            } else {
                strategy.handle(ctx, message);
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 处理异常
        log.error("[gf]channel exception caught in GfMessageHandler", cause);
        ctx.close();  // 关闭连接
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 当连接建立时的处理逻辑
        log.info("[gf]channel connection active: {}", ctx.channel().remoteAddress());
        super.channelActive(ctx);
        // 查询机器人编码
        byte[] date = new byte[]{(byte)0x79,(byte)0x12,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
        GfMessage gfMessage = new GfMessage(date);
        ctx.writeAndFlush(gfMessage);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //离线状态
        //if (Objects.equals(ctx, GfToolkit.ctx)) {
        //    RobotOnlineEventDto dto = new RobotOnlineEventDto();
        //    dto.setOnlineStatus(0);
        //    SpringUtil.getApplicationContext().publishEvent(dto);
        //    //删除上下文
        //    GfToolkit.ctx = null;
        //    log.info("[gf] robot offline ,clear ctx");
        //}
        ////当连接关闭时的处理逻辑
        //log.info("[gf]channel connection inactive: {}", ctx.channel().remoteAddress());
        //super.channelInactive(ctx);
        //离线状态
        if (Objects.equals(ctx, GfToolkit.ctx)) {
            if (GfToolkit.relayCtx==null || GfToolkit.relayCtx.isRemoved()) {
                RobotOnlineEventDto dto = new RobotOnlineEventDto();
                dto.setOnlineStatus(0);
                SpringUtil.getApplicationContext().publishEvent(dto);
                //删除上下文
                GfToolkit.ctx = null;
                log.info("[gf] robot offline ,clear ctx");
            }
        }
        if (Objects.equals(ctx, GfToolkit.relayCtx)){
            RobotOnlineEventDto dto = new RobotOnlineEventDto();
            dto.setOnlineStatus(0);
            SpringUtil.getApplicationContext().publishEvent(dto);
            //删除上下文
            GfToolkit.relayCtx = null;
            log.info("[gf] robot offline ,clear relayCtx");
        }
        //当连接关闭时的处理逻辑
        log.info("[gf]channel connection inactive: {}", ctx.channel().remoteAddress());
        super.channelInactive(ctx);
    }


    /**
     * 简单处理一些没有子命令的消息
     *
     * @param ctx
     * @param message
     */
    private void simpleHandle(ChannelHandlerContext ctx, GfMessage message) {
        // 获取消息中的数据
        byte[] data = message.getData();
        // 分配 ByteBuf 并将数据写入
        ByteBuf buffer = ctx.alloc().buffer(data.length);
        buffer.writeBytes(data);
        try {
            // 读取命令字节
            int cmd = buffer.readByte() & 0xFF;// 转换成无符号
            switch (cmd) {
                case 0x02: {
                    //首次连接会收到
                    break;
                }
                case 0xF2: {
                    byte ack = buffer.readByte();//0x00：获得成功 0x01：获得失败
                    byte status = buffer.readByte();//0：非升级过程 1：升级过程
                    int supportMaxLength = buffer.readIntLE();//支持固件的最大总长度
                    short supportBlockLength = buffer.readShortLE();//控制板支持分块长度 512字节
                    short sendInterval = buffer.readShortLE();//控制板支持上位机发送时间间隔 单位ms
                    short outTime = buffer.readShortLE();//控制板超时退出时间 单位ms
                    log.info("[gf]firmware update status:{},support info:max length:{},block length:{},send interval:{},outTime:{}",status,supportMaxLength,supportBlockLength,sendInterval,outTime);
                    GfToolkit.release(message, false, ack==(byte)0x00);
                    break;
                }
                case 0xF4: {
                    //设置当前需要升级的固件信息
                    boolean result = buffer.readByte()==0x00;
                    GfToolkit.release(message, false, result);
                    break;
                }
                case 0xF5: {
                    //发送固件数据
                    byte ack = buffer.readByte();//0x00：接收成功 0x01：接收失败 0x02：数据出错 0x03：固件块总数出错 0x04：下一数块块序号出错 0x05：固件CRC出错 0x06：固件总长度不对 0x07：未知命令
                    short blockSn = buffer.readShortLE();
                    log.info("[gf]send firmware data block sn{},ack{}",blockSn,ack);
                    GfToolkit.release(message, false, ack==(byte)0x00);
                    break;
                }
                default:
                    log.warn("[gf] unknown main cmd: {},strategy no found!", String.format("%02X", cmd));
                    break;
            }

        } catch (Exception e) {
            log.warn("[gf]simpleHandle error", e);
        } finally {
            // 确保 ByteBuf 在使用完后释放，防止内存泄漏
            buffer.release();
        }

    }


}
